package com.ruoyi.cc.service.impl;

import com.ruoyi.cc.DTO.QueueConsumeDTO;
import com.ruoyi.cc.DTO.QueueCreateDTO;
import com.ruoyi.cc.domain.*;
import com.ruoyi.cc.mapper.MerchantMapper;
import com.ruoyi.cc.service.IMerchantService;
import org.quartz.*;
import org.springframework.amqp.AmqpConnectException;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class MerchantServiceImpl implements IMerchantService {
    @Autowired
    private MerchantMapper merchantMapper;
    /**
     * 注入RabbitAdmin：动态创建队列
     */
    @Resource
    private AmqpAdmin amqpAdmin;

    /**
     * 注入RabbitTemplate：发送消息到队列
     */
    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 注入RedisTemplate：存储队列状态（名称、创建时间、延迟时间）
     */
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 注入Quartz调度器：创建定时任务
     */
    @Resource
    private Scheduler scheduler;
     /**
      * 查询商户列表
      *
      * @return 商户列表
      */
    @Override
    public List<Merchant> selectMerchantList(Merchant merchant) {
        return merchantMapper.selectMerchantList(merchant);
    }
     /**
      * 查询商户图片列表
      *
      * @return 商户图片列表
      */
    @Override
    public List<MerchantImgs> selectMerchantImgList(MerchantImgs merchantImgs) {
        return merchantMapper.selectMerchantImgList(merchantImgs);
    }
     /**
      * 根据店铺id查询服务详情列表
      *
      * @return 服务详情列表
      */
    @Override
    public List<ServiceDetails> selectServiceDetailsListByMerchantId(ServiceDetails serviceDetails) {
        return merchantMapper.selectServiceDetailsListByMerchantId(serviceDetails);
    }
     /**
      * 根据店铺id查询评价列表
      *
      * @return 评价列表
      */
    @Override
    public List<evaluate> selectEvaluateListByMerchantId(evaluate evaluate) {
        return merchantMapper.selectEvaluateListByMerchantId(evaluate);
    }
     /**
      * 查询评价数量
      *
      * @return 评价数量
      */
    @Override
    public Integer selectEvaluateCountByMerchantIdAndUserId(evaluate evaluate) {
        return merchantMapper.selectEvaluateCountByMerchantIdAndUserId(evaluate);
    }
     /**
      * 提交维修预约的订单
      */
    @Override
    public Integer insertRepairReservation(repairReservation repairReservation) {
        return merchantMapper.insertRepairReservation(repairReservation);
    }
     /**
      * 查询车辆类型列表
      *
      * @return 车辆类型列表
      */
    @Override
    public List<carType> selectCarTypeList() {
        return merchantMapper.selectCarTypeList();
    }
     /**
      * 添加订单
      *
      * @return 订单列表
      */
    @Override
    public Integer insertOrder(Order order) {
        return merchantMapper.insertOrder(order);
    }

    // 从配置中读取Redis键前缀（若未配置则使用默认值，避免键冲突）
    @Value("${rabbit.queue.redis-key-prefix:rabbit:queue:}")
    private String redisKeyPrefix;
    /**
     * 创建队列并添加定时删除任务
     * @param dto 前端传入的请求参数（队列名、延迟时间、消息数量）
     */
    public void createQueue(QueueCreateDTO dto) {
        String queueName = dto.getName();
        Integer lastTime = dto.getLastTime();
        Integer number = dto.getNumber();

        // 1. 验证队列是否已存在（避免重复创建）
        boolean queueExists = false;
        try {
            // 使用RabbitMQ原生的被动声明方式：仅检查队列是否存在，不创建队列
            rabbitTemplate.execute(channel -> {
                channel.queueDeclarePassive(queueName); // 队列存在则返回队列信息，不存在则抛出异常
                return null;
            });
            queueExists = true; // 未抛出异常，说明队列存在
        } catch (Exception e) {
            // 捕获到异常，说明队列不存在
            queueExists = false;
        }

        if (queueExists) {
            throw new RuntimeException("队列[" + queueName + "]已存在，请更换名称");
        }
        // 2. 动态创建RabbitMQ队列
        // 参数说明：队列名、是否持久化、是否排他（仅当前连接可见）、是否自动删除（无消费者时删除）、额外参数
        Queue queue = new Queue(queueName, true, false, false, new HashMap<>());
        amqpAdmin.declareQueue(queue); // 声明队列（创建队列）
        System.out.println("队列[" + queueName + "]创建成功");

        // 3. 发送number条消息到队列，消息内容为"领取成功"
        for (int i = 0; i < number; i++) {
            rabbitTemplate.convertAndSend(queueName, "领取成功"); // 发送消息（队列名、消息内容）
        }
        System.out.println("已向队列[" + queueName + "]发送" + number + "条消息");

        // 4. 存储队列信息到Redis（key：queue:队列名，value：延迟时间），过期时间=延迟时间+60秒（避免残留）
        Map<String, Object> queueInfo = new HashMap<>();
        queueInfo.put("lastTime", lastTime);
        queueInfo.put("createTime", System.currentTimeMillis());
        redisTemplate.opsForValue().set(
                "queue:" + queueName,
                queueInfo,
                lastTime + 60,
                java.util.concurrent.TimeUnit.SECONDS
        );
        System.out.println("队列信息已存入Redis，过期时间：" + (lastTime + 60) + "秒");

        // 5. 创建Quartz定时任务：延迟lastTime秒后执行删除队列
        try {
            createDeleteQueueJob(queueName, lastTime);
        } catch (SchedulerException e) {
            throw new RuntimeException("创建定时删除任务失败", e);
        }
    }

    /**
     * 创建定时删除队列的Quartz任务
     * @param queueName 队列名称
     * @param lastTime 延迟时间（秒）
     * @throws SchedulerException Quartz调度器异常
     */
    private void createDeleteQueueJob(String queueName, Integer lastTime) throws SchedulerException {
        // 5.1 定义JobDetail：绑定DeleteQueueJob，设置任务参数
        JobDetail jobDetail = JobBuilder.newJob(com.cc.rabbittestdemo.Task.DeleteQueueJob.class)
                .withIdentity("deleteQueueJob:" + queueName, "queueGroup") // 任务唯一标识（名称+分组）
                .usingJobData("queueName", queueName) // 传入队列名称参数
                .usingJobData("lastTime", lastTime) // 传入延迟时间参数
                .storeDurably(false) // 任务是否持久化（无触发器时是否保留）
                .build();

        // 5.2 定义Trigger：延迟lastTime秒后执行一次
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("deleteQueueTrigger:" + queueName, "queueGroup") // 触发器唯一标识
                .startAt(new java.util.Date(System.currentTimeMillis() + lastTime * 1000)) // 触发时间=当前时间+延迟时间（毫秒）
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withRepeatCount(0)) // 执行次数：仅一次
                .build();

        // 5.3 将JobDetail和Trigger注册到Quartz调度器
        scheduler.scheduleJob(jobDetail, trigger);
        System.out.println("定时删除任务创建成功：队列[" + queueName + "]将在" + lastTime + "秒后删除");
    }

    /**
     * 消费指定队列的单条消息
     * @param dto 入参DTO（包含队列名称name）
     * @return 消费到的消息内容（字符串格式）
     */
    public String consumeMessage(QueueConsumeDTO dto) {
        // 1. 获取入参中的队列名称
        String queueName = dto.getName();
        System.out.println("消费队列：" + queueName);

        try {
            // 2. 校验队列是否存在（被动声明：仅查询，不存在则抛出异常）
            // queueDeclarePassive：RabbitMQ原生方法，无此队列时会抛出异常
            amqpAdmin.declareQueue(new Queue(queueName, true));
        } catch (Exception e) {
            // 3. 捕获队列不存在异常，抛出友好提示（若依全局异常处理器会统一处理）
            throw new RuntimeException("队列[" + queueName + "]不存在，请先创建队列");
        }

        try {
            // 4. 从指定队列接收单条消息（非阻塞：无消息时返回Null，超时时间默认5秒）
            // receive方法：获取队列头部第一条消息并从队列中移除（即"消费"操作）
            Message message = rabbitTemplate.receive(queueName);

            // 5. 判断是否获取到消息
            if (message == null) {
                // 无消息时抛出提示，避免返回Null导致前端处理异常
                throw new RuntimeException("该优惠券已领取完");
            }

            // 6. 解析消息体（若依默认消息序列化方式为字节数组，需转为UTF-8字符串）
            // getBody()：获取消息体字节数组
            // StandardCharsets.UTF_8：指定编码格式，避免中文乱码
            String messageContent = new String(message.getBody(), StandardCharsets.UTF_8);

            // 7. 返回解析后的消息内容
            return messageContent;

        } catch (AmqpConnectException e) {
            // 8. 捕获RabbitMQ连接异常（如服务未启动、配置错误）
            throw new RuntimeException("RabbitMQ连接失败，请检查服务状态或配置");
        } catch (Exception e) {
            // 9. 捕获其他未知异常（如消息格式错误等）
            throw new RuntimeException(e.getMessage());
        }
    }
    /**
     * 改变优惠券状态
     */
    @Override
    public Integer updateCouponStatus(String queueName) {
        return merchantMapper.updateCouponStatus(queueName);
    }
     /**
      * 增加优惠券
      */
    @Override
    public Integer insertCoupon(Coupon coupon) {
        return merchantMapper.insertCoupon(coupon);
    }
     /**
      * 查询所有优惠券列表
      *
      * @return 优惠券列表
      */
    @Override
    public List<Coupon> selectAllCouponList() {
        return merchantMapper.selectAllCouponList();
    }
    /**
     * 查询每个用户自己未领取的优惠券列表
     *
     * @return 优惠券列表
     */
    @Override
    public List<Coupon> selectCouponList(Coupon coupon) {
        return merchantMapper.selectCouponList(coupon);
    }
    /**
     * 查询每个用户自己已领取过的且可再次领取的优惠券列表
     *
     * @return 优惠券列表
     */
    @Override
    public List<Coupon> selectCouponListAgain(Coupon coupon) {
        return merchantMapper.selectCouponListAgain(coupon);
    }
    /**
     * 领取优惠券成功后在用户表中增加该优惠券
     */
    @Override
    public Integer insertCouponToUser(userCoupon userCoupon) {
        return merchantMapper.insertCouponToUser(userCoupon);
    }
    /**
     * 领取已领取过的但可再次领取的优惠券成功后在用户优惠券表中增加该优惠券的数量
     */
    @Override
    public Integer updateUserCouponStatus(userCoupon userCoupon) {
        return merchantMapper.updateUserCouponStatus(userCoupon);
    }


}
